package core

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/joho/godotenv"
	"github.com/spf13/viper"
)

// Config 系统配置
type Config struct {
	App     AppConfig
	Server  ServerConfig
	DB      DBConfig
	JWT     JWTConfig
	Storage StorageConfig
	Redis   RedisConfig
	Log     LogConfig
	Monitor MonitorConfig
}

// AppConfig 应用配置
type AppConfig struct {
	Name    string
	Version string
	Env     string
}

// ServerConfig 服务器配置
type ServerConfig struct {
	Port            string
	ReadTimeout     time.Duration
	WriteTimeout    time.Duration
	ShutdownTimeout time.Duration
}

// DBConfig 数据库配置
type DBConfig struct {
	Driver   string
	Host     string
	Port     string
	Username string
	Password string
	Name     string
	Charset  string
	MaxIdle  int
	MaxOpen  int
}

// JWTConfig JWT配置
type JWTConfig struct {
	Secret string
	Expire time.Duration
}

// StorageConfig 存储配置
type StorageConfig struct {
	Driver       string
	LocalPath    string
	OSSEndpoint  string
	OSSAccessKey string
	OSSSecretKey string
	OSSBucket    string
}

// RedisConfig Redis配置
type RedisConfig struct {
	Host     string
	Port     string
	Password string
	DB       int
	PoolSize int
}

// LogConfig 日志配置
type LogConfig struct {
	Level     string
	Filename  string
	MaxSize   int
	MaxAge    int
	MaxBackup int
}

// MonitorConfig 监控配置
type MonitorConfig struct {
	PrometheusEnabled bool
	PrometheusPath    string
	JaegerEnabled     bool
	JaegerEndpoint    string
}

var (
	config Config
	once   sync.Once
)

// GetConfig 获取配置
func GetConfig() *Config {
	once.Do(func() {
		// 加载环境变量
		loadEnv()

		// 初始化配置
		config = Config{
			App: AppConfig{
				Name:    getEnv("APP_NAME", "BookStack"),
				Version: getEnv("APP_VERSION", "1.0.0"),
				Env:     getEnv("APP_ENV", "dev"),
			},
			Server: ServerConfig{
				Port:            getEnv("SERVER_PORT", "8080"),
				ReadTimeout:     parseDuration(getEnv("SERVER_READ_TIMEOUT", "60s")),
				WriteTimeout:    parseDuration(getEnv("SERVER_WRITE_TIMEOUT", "60s")),
				ShutdownTimeout: parseDuration(getEnv("SERVER_SHUTDOWN_TIMEOUT", "30s")),
			},
			DB: DBConfig{
				Driver:   getEnv("DB_DRIVER", "mysql"),
				Host:     getEnv("DB_HOST", "localhost"),
				Port:     getEnv("DB_PORT", "3306"),
				Username: getEnv("DB_USERNAME", "root"),
				Password: getEnv("DB_PASSWORD", "123456"),
				Name:     getEnv("DB_NAME", "bookstack"),
				Charset:  getEnv("DB_CHARSET", "utf8mb4"),
				MaxIdle:  parseInt(getEnv("DB_MAX_IDLE_CONNS", "10")),
				MaxOpen:  parseInt(getEnv("DB_MAX_OPEN_CONNS", "100")),
			},
			JWT: JWTConfig{
				Secret: getEnv("JWT_SECRET_KEY", "your-secret-key"),
				Expire: parseDuration(getEnv("JWT_EXPIRES_IN", "24h")),
			},
			Storage: StorageConfig{
				Driver:       getEnv("STORAGE_DRIVER", "local"),
				LocalPath:    getEnv("STORAGE_LOCAL_PATH", "storage"),
				OSSEndpoint:  getEnv("STORAGE_OSS_ENDPOINT", ""),
				OSSAccessKey: getEnv("STORAGE_OSS_ACCESS_KEY_ID", ""),
				OSSSecretKey: getEnv("STORAGE_OSS_ACCESS_KEY_SECRET", ""),
				OSSBucket:    getEnv("STORAGE_OSS_BUCKET", ""),
			},
			Redis: RedisConfig{
				Host:     getEnv("REDIS_HOST", "localhost"),
				Port:     getEnv("REDIS_PORT", "6379"),
				Password: getEnv("REDIS_PASSWORD", ""),
				DB:       parseInt(getEnv("REDIS_DB", "0")),
				PoolSize: parseInt(getEnv("REDIS_POOL_SIZE", "100")),
			},
			Log: LogConfig{
				Level:     getEnv("LOG_LEVEL", "debug"),
				Filename:  getEnv("LOG_FILENAME", "./logs/bookstack.log"),
				MaxSize:   parseInt(getEnv("LOG_MAX_SIZE", "100")),
				MaxAge:    parseInt(getEnv("LOG_MAX_AGE", "30")),
				MaxBackup: parseInt(getEnv("LOG_MAX_BACKUPS", "10")),
			},
			Monitor: MonitorConfig{
				PrometheusEnabled: parseBool(getEnv("MONITOR_PROMETHEUS_ENABLED", "true")),
				PrometheusPath:    getEnv("MONITOR_PROMETHEUS_PATH", "/metrics"),
				JaegerEnabled:     parseBool(getEnv("MONITOR_JAEGER_ENABLED", "true")),
				JaegerEndpoint:    getEnv("MONITOR_JAEGER_ENDPOINT", "http://localhost:14268/api/traces"),
			},
		}
	})

	return &config
}

// loadEnv 加载环境变量
func loadEnv() {
	// 获取执行路径
	execPath, err := os.Executable()
	if err != nil {
		execPath = "."
	}

	// 尝试从执行目录加载
	envFile := filepath.Join(filepath.Dir(execPath), ".env")

	// 如果执行目录下没有，尝试从当前目录加载
	if _, err := os.Stat(envFile); os.IsNotExist(err) {
		envFile = ".env"
	}

	// 如果存在.env文件，则加载
	if _, err := os.Stat(envFile); err == nil {
		if err := godotenv.Load(envFile); err != nil {
			log.Printf("加载.env文件失败: %v\n", err)
		}
	}
}

// getEnv 获取环境变量，不存在则返回默认值
func getEnv(key, defaultValue string) string {
	if value, exists := os.LookupEnv(key); exists {
		return value
	}

	return viper.GetString(key)
}

// parseDuration 解析持续时间
func parseDuration(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Printf("解析时间失败, 使用默认值: %s, 错误: %v\n", s, err)
		return 60 * time.Second
	}
	return d
}

// parseInt 解析整数
func parseInt(s string) int {
	var v int
	_, err := fmt.Sscanf(s, "%d", &v)
	if err != nil {
		log.Printf("解析整数失败, 使用默认值: %s, 错误: %v\n", s, err)
		return 0
	}
	return v
}

// parseBool 解析布尔值
func parseBool(s string) bool {
	switch s {
	case "true", "True", "TRUE", "1":
		return true
	default:
		return false
	}
}
